package com.example.demo.use_demo.a_encrypt;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 加密工具
 */
@Slf4j
public class EncryptUtil {

	//================================================================================================================//

	/**
	 * AES加密
	 */
	public static String aesEncryptWithSalt(String content, String salt) {
		if (null == content) {
			return null;
		}
		try {
			Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
			cipher.init(Cipher.ENCRYPT_MODE, KeyInitializer.secretKeySpecInit(salt));
			byte[] result = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
			return org.apache.commons.codec.binary.Base64.encodeBase64String(result);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * AES解密
	 */
	public static String aesDecryptWithSalt(String content, String salt) {
		if (null == content) {
			return null;
		}
		try {
			Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
			cipher.init(Cipher.DECRYPT_MODE, KeyInitializer.secretKeySpecInit(salt));
			byte[] result = cipher.doFinal(org.apache.commons.codec.binary.Base64.decodeBase64(content));
			return new String(result, StandardCharsets.UTF_8);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	//================================================================================================================//

	/**
	 * AES加密
	 * @param content 加密的内容
	 * @return 加密结果
	 */
	public static String aesEncryptWithKey(String content, String key) {
		if (StringUtils.isBlank(content)) {
			return content;
		}
		try {
			KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
			keyGenerator.init(256,new SecureRandom(key.getBytes()));
			SecretKey secretKey = keyGenerator.generateKey();
			byte[] secretKeyEncoded = secretKey.getEncoded();
			SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyEncoded, "AES");

			Cipher encryptCipher = Cipher.getInstance("AES");
			encryptCipher.init(Cipher.ENCRYPT_MODE,secretKeySpec);
			byte[] encryptBytes = encryptCipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
			return Base64.getEncoder().encodeToString(encryptBytes);
		} catch (Exception e) {
			log.error("加密异常",e);
		}
		return content;
	}

	/**
	 * AES解密
	 * @param encryptData 解密的内容
	 * @return 解密结果
	 */
	public static String aesDecryptWithKey(String encryptData, String key) {
		if (StringUtils.isBlank(encryptData)) {
			return encryptData;
		}
		try {
			KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
			keyGenerator.init(256,new SecureRandom(key.getBytes()));
			SecretKey secretKey = keyGenerator.generateKey();
			byte[] secretKeyEncoded = secretKey.getEncoded();
			SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyEncoded, "AES");

			Cipher decryptCipher = Cipher.getInstance("AES");
			decryptCipher.init(Cipher.DECRYPT_MODE,secretKeySpec);
			byte[] decryptBytes = decryptCipher.doFinal(Base64.getDecoder().decode(encryptData));
			return new String(decryptBytes, StandardCharsets.UTF_8);
		} catch (Exception e) {
			log.error("解密异常", e);
		}
		return encryptData;
	}

	//================================================================================================================//

	/**
	 * ：加密步骤： 1、换位号码中两组数字：第二位和第六位交换，第三位和第五位交换 2、将全部号码转换为对应的字符 3、任意位置插入三个随机数字 4、在步骤C之后的字符串前加上”~”
	 */
	public static String encryptPhoneOld(String phoneStr) {
		// 1.换位号码中两组数字：第二位和第六位交换，第三位和第五位交换
		phoneStr = changeNum(phoneStr);
		// 2.将全部号码转换为对应的字符
		phoneStr = getPhoneStr(phoneStr);
		// 3.任意位置插入三个随机数字
		 phoneStr = insertNum(phoneStr);
		// 4.在步骤C之后的字符串前加上”~”
		 phoneStr = prefixStr(phoneStr);
		return phoneStr;
	}

	/**
	 * ：解密步骤： 1、去除字符串前”~” 2、去除所有数字 3、将剩余字母全部转换为对应的数字 4、换位号码中两组数字：第二位和第六位交换，第三位和第五位交换
	 */
	public static String decryptPhoneOld(String phoneStr) {
		if (!NumberUtil.isNumber(phoneStr)) {
			// 1.去除字符串前”~”
			 phoneStr = filterStr(phoneStr);
			// 2.去除所有数字
			 phoneStr = removeNum(phoneStr);
			// 3.将剩余字母全部转换为对应的数字
			phoneStr = getPhoneNum(phoneStr);
			// 4.换位号码中两组数字：第二位和第六位交换，第三位和第五位交换
			phoneStr = changeNum(phoneStr);
		}
		return phoneStr;
	}

	/***
	 * 换位号码中两组数字：第二位和第六位交换，第三位和第五位交换，位数号按从左往右数 13510642584 16015342584
	 */
	public static String changeNum(String val) {

		if (!StringUtils.isEmpty(val)) {
			StringBuilder str = new StringBuilder();
			char[] phone = val.toCharArray();
			for (int i = 0; i < phone.length; i++) {
				if (i == 1 || i == 2 || i == 4 || i == 5) {
					if (i == 1) {
						str.append(phone[5]);
					}
					if (i == 2) {
						str.append(phone[4]);
					}
					if (i == 4) {
						str.append(phone[2]);
					}
					if (i == 5) {
						str.append(phone[1]);
					}
				} else {
					str.append(phone[i]);
				}
			}
			return str.toString();
		}
		return val;
	}

	/**
	 * 数字 0 1 2 3 4 5 6 7 8 9 字母 b a c g h k o w q p
	 *
	 * @param phoneNum 电话号码
	 */
	public static String getPhoneStr(String phoneNum) {
		StringBuilder returnStr = new StringBuilder();
		if (phoneNum != null && phoneNum.length() > 0) {
			byte[] obj = phoneNum.getBytes();
			for (int i = 0; i < obj.length; i++) {
				returnStr.append(getLetter(String.valueOf(phoneNum.charAt(i))));
			}
		}
		return returnStr.toString();
	}

	/**
	 * 字母转数字 字母 b a c g h k o w q p 数字 0 1 2 3 4 5 6 7 8 9
	 *
	 * @param phoneLetter 电话号码字母串
	 */
	public static String getPhoneNum(String phoneLetter) {
		StringBuilder returnStr = new StringBuilder();
		if (phoneLetter != null && phoneLetter.length() > 0) {
			byte[] obj = phoneLetter.getBytes();
			for (int i = 0; i < obj.length; i++) {
				returnStr.append(getMapData().get(String.valueOf(phoneLetter.charAt(i))));
			}
		}
		return returnStr.toString();
	}

	/**
	 * 去除所有数字
	 */
	public static String removeNum(String val) {
		return val.replaceAll("\\d+", "");
	}

	/**
	 * 随机插入3个数字
	 */
	public static String insertNum(String val) {
		String num = RandomUtil.randomNumbers(3);
		// 往指定长度字符串加入随机数字
		for (int i = 0; i < num.length(); i++) {
			int inNum = RandomUtil.randomInt(0,10);
			val = val.substring(0, Math.min(inNum, val.length())) + num.charAt(i)
					+ val.substring(Math.min(inNum, val.length()), val.length());
		}
		return val;
	}

	/**
	 * 字符串前增加“~”
	 */
	public static String prefixStr(String val) {
		return "~" + val;
	}

	/**
	 * 过滤字符串前的“~”
	 */
	public static String filterStr(String val) {
		if (val != null && val.contains("~")) {
			return val.substring(1, val.length());
		}
		if (val != null && val.contains("%")) {
			val = val.replace("%7E", "~").replace("%7e", "~");
			return val.substring(1, val.length());
		}
		return val;
	}

	/**
	 * 通过Map值获取key
	 */
	public static String getLetter(String val) {
		for (Entry<String, String> entry : getMapData().entrySet()) {
			if (val.equals(entry.getValue())) {
				return String.valueOf(entry.getKey());
			}
		}
		return val;
	}

	/**
	 * 字母 b a c g h k o w q p 数字 0 1 2 3 4 5 6 7 8 9
	 */
	public static Map<String, String> getMapData() {
		Map<String, String> map = new HashMap<String, String>(16);
		map.put("b", "0");
		map.put("a", "1");
		map.put("c", "2");
		map.put("g", "3");
		map.put("h", "4");
		map.put("k", "5");
		map.put("o", "6");
		map.put("w", "7");
		map.put("q", "8");
		map.put("p", "9");
		return map;
	}

	//================================================================================================================//

}
